﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO.Compression;

namespace SimpleSM
{
    public partial class Main : Form
    {
        [DllImport("shell32.dll", EntryPoint = "ExtractIcon")]
        extern static IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);

        private bool FormLoaded = false;

        private string sessionName = "";
        private string sessionHost = "";
        private string sessionInfo = "";
        private int sessionId = 0;

        public Main()
        {
            InitializeComponent();
            this.Width = Properties.Settings.Default.width;
            this.Height = Properties.Settings.Default.height;
            splitContainer1.SplitterDistance = Properties.Settings.Default.splitterDistance;
        }

        static public Icon GetIcon(int index)
        {
            IntPtr Hicon = ExtractIcon(IntPtr.Zero, @"C:\WINDOWS\System32\shell32.dll", index);
            Icon icon = Icon.FromHandle(Hicon);
            return icon;
        }

        private void btOptions_Click(object sender, EventArgs e)
        {
            new Options().ShowDialog();
            if (treeView1.SelectedNode != null)
            {
                if (treeView1.SelectedNode.Name[0] == 'S')
                {
                    this.RefreshDGV();
                }
            }
        }

        private void RefreshDGV()
        {
            dataGridView1.Rows.Clear();
            DataTable dt = new SessionT().GetA(this.sessionId);
            string app = "";
            StringBuilder args = new StringBuilder();
            foreach (DataRow row in dt.Rows)
            {
                app = row[2].ToString();
                args.Clear();
                args.Insert(0, row[3].ToString());
                args.Replace("%host%", tbHost.Text);
                args.Replace("%port%", row[4].ToString());
                args.Replace("%user%", row[5].ToString());
                args.Replace("%pass%", row[6].ToString());
                args.Replace("%arg1%", row[7].ToString());
                args.Replace("%arg2%", row[8].ToString());
                dataGridView1.Rows.Add(row[0].ToString(), row[1].ToString(), row[5].ToString(), new Button(), app, args.ToString());
            }
        }

        private void btAddType_Click(object sender, EventArgs e)
        {
            new SessionType(this.sessionId).ShowDialog();
            this.RefreshDGV();
        }

        private void btCopyFrom_Click(object sender, EventArgs e)
        {
            new CopyTypesFrom(this.sessionId).ShowDialog();
            this.RefreshDGV();
        }

        private void btNewGroup_Click(object sender, EventArgs e)
        {
            Group newGroup = new Group();
            if (treeView1.SelectedNode == null)
            {
                newGroup.Add("new group");
            }
            else
            {
                if (treeView1.SelectedNode.Name[0] == 'G')
                {
                    newGroup.Add("new group", int.Parse(treeView1.SelectedNode.Name.Substring(1, treeView1.SelectedNode.Name.Length - 1)));
                }
                else
                {
                    if (treeView1.SelectedNode.Parent == null)
                    {
                        newGroup.Add("new group");
                    }
                    else
                    {
                        newGroup.Add("new group", int.Parse(treeView1.SelectedNode.Parent.Name.Substring(1, treeView1.SelectedNode.Parent.Name.Length - 1)));
                    }
                }
            }
            int nodeid = newGroup.LastInsertId();
            this.RefreshTreeView();
            foreach (TreeNode node in treeView1.Nodes)
            {
                if (node.Name == "G" + nodeid.ToString())
                {
                    node.BeginEdit();
                }
                if (node.Nodes.Count > 0)
                {
                    selectNode(node, "G" + nodeid.ToString());
                }
            }
        }

        private void selectNode(TreeNode node, string key)
        {
            foreach (TreeNode n in node.Nodes)
            {
                if (n.Name == key)
                {
                    n.BeginEdit();
                }
                if (n.Nodes.Count > 0)
                {
                    selectNode(n, key);
                }
            }
        }

        private void Main_Shown(object sender, EventArgs e)
        {
            bool db = false;
            if (Properties.Settings.Default.database != "")
            {
                if (File.Exists(Properties.Settings.Default.database))
                {
                    db = true;
                    if (Properties.Settings.Default.backupDir != "")
                    {
                        if (Directory.Exists(Properties.Settings.Default.backupDir))
                        {
                            if (Properties.Settings.Default.backupDB == 1)
                            {
                                Main.backupDB("_" + DateTime.Now.ToShortDateString().Replace('-', '_'));
                            }
                            if (Properties.Settings.Default.backupDB == 2)
                            {
                                Main.backupDB("_" + DateTime.Now.ToShortDateString().Replace('-', '_') + "_" + DateTime.Now.ToShortTimeString().Replace(':', '_'));
                            }
                        }
                    }
                }
            }
            if (db == false)
            {
                if (MessageBox.Show("SimpleSM create new database, select file to create.", "Database...", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
                {
                    if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                    {
                        Properties.Settings.Default.database = saveFileDialog1.FileName;
                        Properties.Settings.Default.Save();
                        new DB().InitDB();
                        db = true;
                    }
                    else
                    {
                        this.Close();
                    }
                }
                else
                {
                    this.Close();
                }
            }
            if (db)
            {
                new DB().Update();
                imageList1.Images.Add("folder", GetIcon(126));
                imageList1.Images.Add("computer", GetIcon(15));
                this.RefreshTreeView();
                this.FormLoaded = true;
            }
            if (Properties.Settings.Default.autostartPagent && Properties.Settings.Default.pagentPath != "" && Properties.Settings.Default.pagentFiles != "")
            {
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = Properties.Settings.Default.pagentPath;
                StringBuilder args = new StringBuilder();
                foreach (string s in Properties.Settings.Default.pagentFiles.Split(';'))
                {
                    args.Append(" \"" + s + "\"");
                }
                startInfo.Arguments = @args.ToString();
                Process.Start(startInfo);
            }
        }

        private void AddNodeTreeView(DataTable dt, DataRow dr, TreeNode node)
        {
            TreeNode node2;
            TreeNode node3;
            DataTable dts;
            foreach (DataRow dr2 in dt.Select("group_id = " + dr[0].ToString()))
            {
                node2 = node.Nodes.Add("G" + dr2[0].ToString(), dr2[1].ToString());
                this.AddNodeTreeView(dt, dr2, node2);
            }
            dts = new Session().GetA(int.Parse(dr[0].ToString()));
            foreach (DataRow rows in dts.Select())
            {
                node3 = node.Nodes.Add("S" + rows[0].ToString(), rows[1].ToString());
                node3.ImageKey = "computer";
                node3.SelectedImageKey = "computer";
            }
            if ((bool)dr[3])
            {
                node.Expand();
            }
        }

        private void RefreshTreeView()
        {
            TreeNode node;
            TreeNode node2;
            treeView1.Nodes.Clear();
            DataTable dt = new Group().Get();
            DataTable dts;
            foreach (DataRow row in dt.Select("group_id is null"))
            {
                node = treeView1.Nodes.Add("G" + row[0].ToString(), row[1].ToString());
                this.AddNodeTreeView(dt, row, node);
            }
            dts = new Session().GetA();
            foreach (DataRow rows in dts.Select())
            {
                node2 = treeView1.Nodes.Add("S" + rows[0].ToString(), rows[1].ToString());
                node2.ImageKey = "computer";
                node2.SelectedImageKey = "computer";
            }
        }

        private void treeView1_AfterExpand(object sender, TreeViewEventArgs e)
        {
            if (this.FormLoaded)
            {
                new Group().Update(true, int.Parse(e.Node.Name.Substring(1, e.Node.Name.Length - 1)));
            }
        }

        private void treeView1_AfterCollapse(object sender, TreeViewEventArgs e)
        {
            if (this.FormLoaded)
            {
                new Group().Update(false, int.Parse(e.Node.Name.Substring(1, e.Node.Name.Length - 1)));
            }
        }

        private void btEditGroup_Click(object sender, EventArgs e)
        {
            if (treeView1.SelectedNode != null)
            {
                if (treeView1.SelectedNode.Name[0] == 'G')
                {
                    treeView1.SelectedNode.BeginEdit();
                }
                else
                {
                    MessageBox.Show("Please select group.", "Warrning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            else
            {
                MessageBox.Show("Please select group.", "Warrning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private void btDeleteGroup_Click(object sender, EventArgs e)
        {
            if (treeView1.SelectedNode != null)
            {
                if (treeView1.SelectedNode.Name[0] == 'G')
                {
                    if (MessageBox.Show("Do you really delete this group (" + treeView1.SelectedNode.Text + ") and nodes in this group?", "Warrning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                    {
                        new Group().Delete(int.Parse(treeView1.SelectedNode.Name.Substring(1, treeView1.SelectedNode.Name.Length - 1)));
                        treeView1.SelectedNode.Remove();
                        treeView1.SelectedNode = null;
                    }
                }
                else
                {
                    if (MessageBox.Show("Do you really delete this session (" + treeView1.SelectedNode.Text + ")?", "Warrning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                    {
                        new Session().Delete(int.Parse(treeView1.SelectedNode.Name.Substring(1, treeView1.SelectedNode.Name.Length - 1)));
                        treeView1.SelectedNode.Remove();
                        tbName.Text = "";
                        tbHost.Text = "";
                        dataGridView1.Rows.Clear();
                        this.EnableSessionControls(false);
                        treeView1.SelectedNode = null;
                    }
                }
            }
            else
            {
                MessageBox.Show("Please select group or session.", "Warrning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private void EnableSessionControls(bool b = true)
        {
            tbName.Enabled = b;
            tbHost.Enabled = b;
            btAddType.Enabled = b;
            btEditType.Enabled = b;
            btDeleteType.Enabled = b;
            btCopyFrom.Enabled = b;
        }

        private void btNewSession_Click(object sender, EventArgs e)
        {
            if (treeView1.SelectedNode == null)
            {
                new Session().Add("New session", "session.new", 0);
            }
            else
            {
                if (treeView1.SelectedNode.Name[0] == 'G')
                {
                    new Session().Add("New session", "session.new", int.Parse(treeView1.SelectedNode.Name.Substring(1, treeView1.SelectedNode.Name.Length -1)));
                }
                else
                {
                    if (treeView1.SelectedNode.Parent != null)
                    {
                        new Session().Add("New session", "session.new", int.Parse(treeView1.SelectedNode.Parent.Name.Substring(1, treeView1.SelectedNode.Parent.Name.Length - 1)));
                    }
                }
            }
            this.RefreshTreeView();
            
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Name[0] == 'S')
            {
                this.EnableSessionControls();
                DataTable dtses = new Session().Get(int.Parse(e.Node.Name.Substring(1, e.Node.Name.Length - 1)));
                tbName.Text = dtses.Rows[0][1].ToString();
                tbHost.Text = dtses.Rows[0][3].ToString();
                tbInfo.Text = dtses.Rows[0][4].ToString();
                this.sessionName = dtses.Rows[0][1].ToString();
                this.sessionHost = dtses.Rows[0][3].ToString();
                this.sessionInfo = dtses.Rows[0][4].ToString();
                this.sessionId = int.Parse(dtses.Rows[0][0].ToString());
                this.RefreshDGV();
            }
            else
            {
                this.sessionName = "";
                this.sessionHost = "";
                tbName.Text = "";
                tbHost.Text = "";
                this.EnableSessionControls(false);
                dataGridView1.Rows.Clear();
            }
        }

        private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
        {
            if (this.FormLoaded)
            {
                Properties.Settings.Default.splitterDistance = splitContainer1.SplitterDistance;
                Properties.Settings.Default.Save();
            }
        }

        private void Main_ResizeEnd(object sender, EventArgs e)
        {
            if (this.FormLoaded)
            {
                Properties.Settings.Default.height = this.Height;
                Properties.Settings.Default.width = this.Width;
                Properties.Settings.Default.splitterDistance = splitContainer1.SplitterDistance;
                Properties.Settings.Default.Save();
            }
        }

        private void treeView1_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            if (e.Label == "" || e.Label == null)
            {
                e.CancelEdit = true;
                return;
            }
            if (e.Node.Name[0] == 'G')
            {
                new Group().Update(e.Label, int.Parse(e.Node.Name.Substring(1, e.Node.Name.Length - 1)));
            }
            else
            {
                new Session().Update(int.Parse(e.Node.Name.Substring(1, e.Node.Name.Length - 1)), e.Label);
                tbName.Text = e.Label;
                this.sessionName = e.Label;
            }
        }

        private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            // Move the dragged node when the left mouse button is used.
            if (e.Button == MouseButtons.Left)
            {
                DoDragDrop(e.Item, DragDropEffects.Move);
            }

            // Copy the dragged node when the right mouse button is used.
            else if (e.Button == MouseButtons.Right)
            {
                DoDragDrop(e.Item, DragDropEffects.Copy);
            }
        }

        private void treeView1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.AllowedEffect;
        }

        private void treeView1_DragOver(object sender, DragEventArgs e)
        {
            // Retrieve the client coordinates of the mouse position.
            Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));

            // Select the node at the mouse position.
            treeView1.SelectedNode = treeView1.GetNodeAt(targetPoint);
        }

        private void treeView1_DragDrop(object sender, DragEventArgs e)
        {
            // Retrieve the client coordinates of the drop location.
            Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));

            // Retrieve the node at the drop location.
            TreeNode targetNode = treeView1.GetNodeAt(targetPoint);

            // Retrieve the node that was dragged.
            TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));

            // Confirm that the node at the drop location is not 
            // the dragged node or a descendant of the dragged node.
            if (!draggedNode.Equals(targetNode) && !ContainsNode(draggedNode, targetNode))
            {
                // If it is a move operation, remove the node from its current 
                // location and add it to the node at the drop location.
                if (e.Effect == DragDropEffects.Move)
                {
                    if (targetNode == null)
                    {
                        draggedNode.Remove();
                        treeView1.Nodes.Add(draggedNode);
                        if (draggedNode.Name[0] == 'G')
                        {
                            new Group().Update(draggedNode.Text, int.Parse(draggedNode.Name.Substring(1, draggedNode.Name.Length - 1)), 0);
                        }
                        else
                        {
                            new Session().Update(int.Parse(draggedNode.Name.Substring(1, draggedNode.Name.Length - 1)), 0);
                        }
                    }
                    else
                    {
                        if (targetNode.Name[0] == 'S')
                        {
                            return;
                        }
                        if (draggedNode.Name[0] == 'G')
                        {
                            new Group().Update(draggedNode.Text, int.Parse(draggedNode.Name.Substring(1, draggedNode.Name.Length - 1)), int.Parse(targetNode.Name.Substring(1, targetNode.Name.Length - 1)));
                        }
                        else
                        {
                            new Session().Update(int.Parse(draggedNode.Name.Substring(1, draggedNode.Name.Length - 1)), int.Parse(targetNode.Name.Substring(1, targetNode.Name.Length - 1)));
                        }
                        draggedNode.Remove();
                        targetNode.Nodes.Add(draggedNode);
                    }
                }

                // If it is a copy operation, clone the dragged node 
                // and add it to the node at the drop location.
                /*else if (e.Effect == DragDropEffects.Copy)
                {
                    targetNode.Nodes.Add((TreeNode)draggedNode.Clone());
                }*/

                // Expand the node at the location 
                // to show the dropped node.
                if (targetNode != null)
                {
                    targetNode.Expand();
                }
            }
        }

        // Determine whether one node is a parent 
        // or ancestor of a second node.
        private bool ContainsNode(TreeNode node1, TreeNode node2)
        {
            // Check the parent node of the second node.
            if (node2 == null) return false;
            if (node2.Parent == null) return false;
            if (node2.Parent.Equals(node1)) return true;

            // If the parent node is not null or equal to the first node, 
            // call the ContainsNode method recursively using the parent of 
            // the second node.
            return ContainsNode(node1, node2.Parent);
        }

        private void tbName_Leave(object sender, EventArgs e)
        {
            if (this.sessionName != tbName.Text)
            {
                if (tbName.Text == "")
                {
                    tbName.Text = sessionName;
                }
                else
                {
                    string sn = "S" + this.sessionId.ToString();
                    new Session().Update(this.sessionId, tbName.Text);
                    this.sessionName = tbName.Text;
                    this.RefreshTreeView();
                    treeView1.SelectedNode = treeView1.Nodes[sn];
                }
            }
        }

        private void tbHost_Leave(object sender, EventArgs e)
        {
            if (this.sessionHost != tbHost.Text)
            {
                if (tbHost.Text == "")
                {
                    tbHost.Text = this.sessionHost;
                }
                else
                {
                    new Session().UpdateHost(this.sessionId, tbHost.Text);
                    this.sessionHost = tbHost.Text;
                    this.RefreshDGV();
                }
            }
        }

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == 3 && e.RowIndex >= 0)
            {
                string app = dataGridView1.Rows[e.RowIndex].Cells[4].Value.ToString();
                string args = dataGridView1.Rows[e.RowIndex].Cells[5].Value.ToString();
                //MessageBox.Show("Run program: " + dataGridView1.Rows[e.RowIndex].Cells[3].Value.ToString() + "\nWith args: " + dataGridView1.Rows[e.RowIndex].Cells[4].Value.ToString());
                if (File.Exists(app))
                {
                    ProcessStartInfo startInfo = new ProcessStartInfo();
                    startInfo.FileName = @app;
                    startInfo.Arguments = @args;
                    Process.Start(startInfo);
                }
                else
                {
                    MessageBox.Show("Application file not found, check file: " + app, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
        }

        private void btEditType_Click(object sender, EventArgs e)
        {
            if (dataGridView1.SelectedRows.Count > 0)
            {
                new SessionType(this.sessionId, int.Parse(dataGridView1.Rows[dataGridView1.SelectedCells[0].RowIndex].Cells[0].Value.ToString())).ShowDialog();
                this.RefreshDGV();
            }
        }

        private void btDeleteType_Click(object sender, EventArgs e)
        {
            if (dataGridView1.SelectedRows.Count > 0)
            {
                if (MessageBox.Show("Do you really delete this action?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    new SessionT().Delete(int.Parse(dataGridView1.Rows[dataGridView1.SelectedCells[0].RowIndex].Cells[0].Value.ToString()));
                    this.RefreshDGV();
                }
            }
        }

        private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Name[0] == 'S')
            {
                if (dataGridView1.Rows.Count > 0)
                {
                    string app = dataGridView1.Rows[0].Cells[4].Value.ToString();
                    string args = dataGridView1.Rows[0].Cells[5].Value.ToString();
                    //MessageBox.Show("Run program: " + dataGridView1.Rows[e.RowIndex].Cells[3].Value.ToString() + "\nWith args: " + dataGridView1.Rows[e.RowIndex].Cells[4].Value.ToString());
                    if (File.Exists(app))
                    {
                        ProcessStartInfo startInfo = new ProcessStartInfo();
                        startInfo.FileName = @app;
                        startInfo.Arguments = @args;
                        Process.Start(startInfo);
                    }
                    else
                    {
                        MessageBox.Show("Application file not found, check file: " + app, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                }
            }
        }

        public static void backupDB(string addFileName = "")
        {
            FileInfo fi = new FileInfo(Properties.Settings.Default.database);
            using (FileStream inFile = fi.OpenRead())
            {
                if ((File.GetAttributes(fi.FullName) & FileAttributes.Hidden) != FileAttributes.Hidden & fi.Extension != ".gz")
                {
                    using (FileStream outFile = File.Create(Properties.Settings.Default.backupDir + "\\" + Path.GetFileNameWithoutExtension(fi.Name) + addFileName + fi.Extension + ".gz"))
                    {
                        using (GZipStream Compress = new GZipStream(outFile, CompressionMode.Compress))
                        {
                            inFile.CopyTo(Compress);
                        }
                    }
                }
            }
        }

        private void tbInfo_Leave(object sender, EventArgs e)
        {
            if (this.sessionInfo != tbInfo.Text)
            {
                this.sessionInfo = tbInfo.Text;
                new Session().UpdateInfo(this.sessionId, this.sessionInfo);
            }
        }
    }
}
